<!doctype HTML>
    <script src="../../resources/testharness.js"></script>
    <script src="../../resources/testharnessreport.js"></script>
    <script>
        // TODO(yosin): We should merge this test into
        // "external/wpt/html/dom/reflection*.*" to avoid duplicated test cases.
        // This test setting various attributes of a elements to JavaScript null

        function resolve(url)
        {
            var a = document.createElement('a');
            a.href = url;
            return a.href;
        }

        function nullTestElementAttribute(elementType, element, attr)
        {
            const expectedValue = attr.expectedNull;
            test(() => {
                if (attr.isException) {
                    assert_throws_dom(expectedValue,
                                      () => element[attr.name] = null);
                    return;
                }
                element[attr.name] = null;
                const actualValue = element[attr.name];
                if (attr.isUrl)
                  assert_equals(actualValue, resolve(expectedValue));
                else
                  assert_equals(actualValue, expectedValue);
            }, `${elementType}.${attr.name}`);
        }

        function runTests()
        {
            // Others to test:
            //  Core DOM
            //    Attr.value (expected: null)
            //    CharacterData.data
            //    ProcessingInstruction.data
            //  Functions

            var listing = [
                {
                    type: 'Node',
                    elementToUse: document.createElement('div'),
                    attributes: [
                        {name: 'nodeValue', expectedNull: null},
                        {name: 'textContent', expectedNull: ''}
                    ]
                },
                {
                    type: 'Element',
                    elementToUse: document.createElementNS('http://example.com/', 'example'),
                    attributes: [
                        {name: 'id', expectedNull: 'null'},
                        {name: 'className', expectedNull: 'null'},
                        {name: 'innerHTML', expectedNull: ''},
                        {name: 'outerHTML',
                         expectedNull: 'NoModificationAllowedError',
                         isException: true}
                    ]
                },
                {
                    type: 'HTMLElement',
                    elementToUse: document.createElement('abbr'),
                    attributes: [
                        {name: 'accessKey', expectedNull: 'null'},
                        {name: 'title', expectedNull: 'null'},
                        {name: 'lang', expectedNull: 'null'},
                        {name: 'dir', expectedNull: ''},
                        {name: 'innerText', expectedNull: ''},
                        {name: 'outerText',
                         expectedNull: 'NoModificationAllowedError',
                         isException: true},
                        {name: 'contentEditable', expectedNull: 'SyntaxError',
                         isException: true}
                    ]
                },
                {
                    type: 'HTMLAnchorElement',
                    elementToUse: document.createElement('a'),
                    attributes: [
                        {name: 'charset', expectedNull: 'null'},
                        {name: 'coords', expectedNull: 'null'},
                        {name: 'download', expectedNull: 'null'},
                        {name: 'href', expectedNull: 'null', isUrl: true},
                        {name: 'hreflang', expectedNull: 'null'},
                        {name: 'name', expectedNull: 'null'},
                        {name: 'ping', expectedNull: 'null'},
                        {name: 'rel', expectedNull: 'null'},
                        {name: 'rev', expectedNull: 'null'},
                        {name: 'shape', expectedNull: 'null'},
                        {name: 'target', expectedNull: 'null'},
                        {name: 'type', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLAreaElement',
                    elementToUse: document.createElement('area'),
                    attributes: [
                        {name: 'alt', expectedNull: 'null'},
                        {name: 'coords', expectedNull: 'null'},
                        {name: 'href', expectedNull: 'null', isUrl: true},
                        {name: 'ping', expectedNull: 'null'},
                        {name: 'shape', expectedNull: 'null'},
                        {name: 'target', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLAudioElement',
                    elementToUse: document.createElement('audio'),
                    attributes: [
                        {name: 'preload', expectedNull: 'metadata'},
                        {name: 'src', expectedNull: 'null', isUrl: true}
                    ]
                },
                {
                    type: 'HTMLBaseElement',
                    elementToUse: document.createElement('base'),
                    attributes: [
                        {name: 'href', expectedNull: 'null', isUrl: true},
                        {name: 'target', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLBlockquoteElement',
                    elementToUse: document.createElement('blockquote'),
                    attributes: [
                        {name: 'cite', expectedNull: 'null', isUrl: true}
                    ]
                },
                {
                    type: 'HTMLBodyElement',
                    elementToUse: document.createElement('body'),
                    attributes: [
                        {name: 'aLink', expectedNull: ''},
                        {name: 'background', expectedNull: 'null'},
                        {name: 'bgColor', expectedNull: ''},
                        {name: 'link', expectedNull: ''},
                        {name: 'text', expectedNull: ''},
                        {name: 'vLink', expectedNull: ''}
                    ]
                },
                {
                    type: 'HTMLBRElement',
                    elementToUse: document.createElement('br'),
                    attributes: [
                        {name: 'clear', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLButtonElement',
                    elementToUse: document.createElement('button'),
                    attributes: [
                        {name: 'formAction', expectedNull: 'null', isUrl: true},
                        {name: 'formEnctype', expectedNull: 'application/x-www-form-urlencoded'},
                        {name: 'formMethod', expectedNull: 'get'},
                        {name: 'formTarget', expectedNull: 'null'},
                        {name: 'name', expectedNull: 'null'},
                        {name: 'type', expectedNull: 'submit'},
                        {name: 'value', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLDivElement',
                    elementToUse: document.createElement('div'),
                    attributes: [
                        {name: 'align', expectedNull: 'null'}
                    ]
                },

                // HTMLDListElement
                // NONE

                {
                    type: 'HTMLEmbedElement',
                    elementToUse: document.createElement('embed'),
                    attributes: [
                        {name: 'align', expectedNull: 'null'},
                        {name: 'height', expectedNull: 'null'},
                        {name: 'name', expectedNull: 'null'},
                        {name: 'src', expectedNull: 'null', isUrl: true},
                        {name: 'type', expectedNull: 'null'},
                        {name: 'width', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLFieldSetElement',
                    elementToUse: document.createElement('fieldset'),
                    attributes: [
                        {name: 'name', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLFontElement',
                    elementToUse: document.createElement('font'),
                    attributes: [
                        {name: 'color', expectedNull: ''},
                        {name: 'face', expectedNull: 'null'},
                        {name: 'size', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLFormElement',
                    elementToUse: document.createElement('form'),
                    attributes: [
                        {name: 'acceptCharset', expectedNull: 'null'},
                        {name: 'action', expectedNull: 'null', isUrl: true},
                        {name: 'autocomplete', expectedNull: 'on'},
                        {name: 'enctype', expectedNull: 'application/x-www-form-urlencoded'},
                        {name: 'encoding', expectedNull: 'application/x-www-form-urlencoded'},
                        {name: 'method', expectedNull: 'get'},
                        {name: 'name', expectedNull: 'null'},
                        {name: 'target', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLFrameElement',
                    elementToUse: document.createElement('frame'),
                    attributes: [
                        {name: 'frameBorder', expectedNull: 'null'},
                        {name: 'longDesc', expectedNull: 'null', isUrl: true},
                        {name: 'marginHeight', expectedNull: ''},
                        {name: 'marginWidth', expectedNull: ''},
                        {name: 'name', expectedNull: 'null'},
                        {name: 'scrolling', expectedNull: 'null'},
                        {name: 'src', expectedNull: 'null', isUrl: true}
                    ]
                },
                {
                    type: 'HTMLFrameSetElement',
                    elementToUse: document.createElement('frameset'),
                    attributes: [
                        {name: 'cols', expectedNull: 'null'},
                        {name: 'rows', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLHeadingElement',
                    // no need to test h2-h6
                    elementToUse: document.createElement('h1'),
                    attributes: [
                        {name: 'align', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLHRElement',
                    elementToUse: document.createElement('hr'),
                    attributes: [
                        {name: 'align', expectedNull: 'null'},
                        {name: 'color', expectedNull: 'null'},
                        {name: 'size', expectedNull: 'null'},
                        {name: 'width', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLHtmlElement',
                    elementToUse: document.createElement('html'),
                    attributes: [
                        {name: 'version', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLIFrameElement',
                    elementToUse: document.createElement('iframe'),
                    attributes: [
                        {name: 'align', expectedNull: 'null'},
                        {name: 'frameBorder', expectedNull: 'null'},
                        {name: 'height', expectedNull: 'null'},
                        {name: 'longDesc', expectedNull: 'null', isUrl: true},
                        {name: 'marginHeight', expectedNull: ''},
                        {name: 'marginWidth', expectedNull: ''},
                        {name: 'name', expectedNull: 'null'},
                        {name: 'scrolling', expectedNull: 'null'},
                        {name: 'src', expectedNull: 'null', isUrl: true},
                        {name: 'srcdoc', expectedNull: 'null'},
                        {name: 'width', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLImageElement',
                    elementToUse: document.createElement('img'),
                    attributes: [
                        {name: 'align', expectedNull: 'null'},
                        {name: 'alt', expectedNull: 'null'},
                        {name: 'border', expectedNull: ''},
                        {name: 'crossOrigin', expectedNull: null},
                        {name: 'longDesc', expectedNull: 'null', isUrl: true},
                        {name: 'lowsrc', expectedNull: 'null', isUrl: true},
                        {name: 'name', expectedNull: 'null'},
                        {name: 'src', expectedNull: 'null', isUrl: true},
                        {name: 'srcset', expectedNull: 'null'},
                        {name: 'useMap', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLInputElement',
                    elementToUse: document.createElement('input'),
                    attributes: [
                        {name: 'accept', expectedNull: 'null'},
                        {name: 'align', expectedNull: 'null'},
                        {name: 'alt', expectedNull: 'null'},
                        {name: 'autocomplete', expectedNull: ''},
                        {name: 'defaultValue', expectedNull: 'null'},
                        {name: 'dirName', expectedNull: 'null'},
                        {name: 'formAction', expectedNull: 'null', isUrl: true},
                        {name: 'formEnctype', expectedNull: 'application/x-www-form-urlencoded'},
                        {name: 'formMethod', expectedNull: 'get'},
                        {name: 'formTarget', expectedNull: 'null'},
                        {name: 'max', expectedNull: 'null'},
                        {name: 'min', expectedNull: 'null'},
                        {name: 'name', expectedNull: 'null'},
                        {name: 'pattern', expectedNull: 'null'},
                        {name: 'placeholder', expectedNull: 'null'},
                        {name: 'src', expectedNull: 'null', isUrl: true},
                        {name: 'step', expectedNull: 'null'},
                        {name: 'type', expectedNull: 'text'},
                        {name: 'useMap', expectedNull: 'null'}
                    ]
                },
                // [TreatNullAs=NullString] is not identical to [TreatNullAs=EmptyString] because
                // null and empty string can be distinguished. A side-effect is that setting
                // HTMLInputElement.value to null does clear the old value. This would be fixed by
                // using [TreatNullAs=EmptyString], but until then test value separately to avoid
                // interference from the defaultValue test.
                {
                    type: 'HTMLInputElement',
                    elementToUse: document.createElement('input'),
                    attributes: [
                        {name: 'value', expectedNull: ''}
                    ]
                },
                {
                    type: 'HTMLLabelElement',
                    elementToUse: document.createElement('label'),
                    attributes: [
                        {name: 'htmlFor', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLLegendElement',
                    elementToUse: document.createElement('legend'),
                    attributes: [
                        {name: 'align', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLLIElement',
                    elementToUse: document.createElement('li'),
                    attributes: [
                        {name: 'type', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLLinkElement',
                    elementToUse: document.createElement('link'),
                    attributes: [
                        {name: 'charset', expectedNull: 'null'},
                        {name: 'href', expectedNull: 'null', isUrl: true},
                        {name: 'hreflang', expectedNull: 'null'},
                        {name: 'media', expectedNull: 'null'},
                        {name: 'rel', expectedNull: 'null'},
                        {name: 'rev', expectedNull: 'null'},
                        {name: 'target', expectedNull: 'null'},
                        {name: 'type', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLMapElement',
                    elementToUse: document.createElement('map'),
                    attributes: [
                        {name: 'name', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLMarqueeElement',
                    elementToUse: document.createElement('marquee'),
                    attributes: [
                        {name: 'behavior', expectedNull: 'null'},
                        {name: 'bgColor', expectedNull: 'null'},
                        {name: 'direction', expectedNull: 'null'},
                        {name: 'height', expectedNull: 'null'},
                        {name: 'width', expectedNull: 'null'}
                    ]
                },

                // HTMLMenuElement
                // NONE

                {
                    type: 'HTMLMetaElement',
                    elementToUse: document.createElement('meta'),
                    attributes: [
                        {name: 'content', expectedNull: 'null'},
                        {name: 'httpEquiv', expectedNull: 'null'},
                        {name: 'name', expectedNull: 'null'},
                        {name: 'scheme', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLModElement',
                    elementToUse: document.createElement('ins'), // same as 'del'
                    attributes: [
                        {name: 'cite', expectedNull: 'null', isUrl: true},
                        {name: 'dateTime', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLObjectElement',
                    elementToUse: document.createElement('object'),
                    attributes: [
                        {name: 'code', expectedNull: 'null'},
                        {name: 'align', expectedNull: 'null'},
                        {name: 'archive', expectedNull: 'null'},
                        {name: 'border', expectedNull: ''},
                        {name: 'codeBase', expectedNull: 'null', isUrl: true},
                        {name: 'codeType', expectedNull: 'null'},
                        {name: 'data', expectedNull: 'null', isUrl: true},
                        {name: 'height', expectedNull: 'null'},
                        {name: 'name', expectedNull: 'null'},
                        {name: 'standby', expectedNull: 'null'},
                        {name: 'type', expectedNull: 'null'},
                        {name: 'useMap', expectedNull: 'null'},
                        {name: 'width', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLOListElement',
                    elementToUse: document.createElement('ol'),
                    attributes: [
                        {name: 'type', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLOptGroupElement',
                    elementToUse: document.createElement('optgroup'),
                    attributes: [
                        {name: 'label', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLOptionElement',
                    elementToUse: document.createElement('option'),
                    attributes: [
                        {name: 'text', expectedNull: 'null'},
                        {name: 'label', expectedNull: 'null'},
                        {name: 'value', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLOutputElement',
                    elementToUse: document.createElement('output'),
                    attributes: [
                        {name: 'name', expectedNull: 'null'},
                        {name: 'defaultValue', expectedNull: 'null'},
                        {name: 'value', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLParagraphElement',
                    elementToUse: document.createElement('p'),
                    attributes: [
                        {name: 'align', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLParamElement',
                    elementToUse: document.createElement('param'),
                    attributes: [
                        {name: 'name', expectedNull: 'null'},
                        {name: 'type', expectedNull: 'null'},
                        {name: 'value', expectedNull: 'null'},
                        {name: 'valueType', expectedNull: 'null'}
                    ]
                },

                // HTMLPreElement
                // NONE

                {
                    type: 'HTMLQuoteElement',
                    elementToUse: document.createElement('q'),
                    attributes: [
                        {name: 'cite', expectedNull: 'null', isUrl:true}
                    ]
                },
                {
                    type: 'HTMLScriptElement',
                    elementToUse: document.createElement('script'),
                    attributes: [
                        {name: 'text', expectedNull: 'null'},
                        {name: 'htmlFor', expectedNull: 'null'},
                        {name: 'event', expectedNull: 'null'},
                        {name: 'charset', expectedNull: 'null'},
                        {name: 'src', expectedNull: 'null', isUrl: true},
                        {name: 'type', expectedNull: 'null'},
                        {name: 'crossOrigin', expectedNull: null}
                    ]
                },
                {
                    type: 'HTMLSelectElement',
                    elementToUse: document.createElement('select'),
                    attributes: [
                        {name: 'value', expectedNull: ''},
                        {name: 'name', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLSourceElement',
                    elementToUse: document.createElement('source'),
                    attributes: [
                        {name: 'src', expectedNull: 'null', isUrl: true},
                        {name: 'type', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLStyleElement',
                    elementToUse: document.createElement('style'),
                    attributes: [
                        {name: 'media', expectedNull: 'null'},
                        {name: 'type', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLTableCaptionElement',
                    elementToUse: document.createElement('caption'),
                    attributes: [
                        {name: 'align', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLTableCellElement',
                    elementToUse: document.createElement('td'),
                    attributes: [
                        {name: 'abbr', expectedNull: 'null'},
                        {name: 'align', expectedNull: 'null'},
                        {name: 'axis', expectedNull: 'null'},
                        {name: 'bgColor', expectedNull: ''},
                        {name: 'ch', expectedNull: 'null'},
                        {name: 'chOff', expectedNull: 'null'},
                        {name: 'headers', expectedNull: 'null'},
                        {name: 'height', expectedNull: 'null'},
                        {name: 'scope', expectedNull: ''},
                        {name: 'vAlign', expectedNull: 'null'},
                        {name: 'width', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLTableColElement',
                    elementToUse: document.createElement('col'),
                    attributes: [
                        {name: 'align', expectedNull: 'null'},
                        {name: 'ch', expectedNull: 'null'},
                        {name: 'chOff', expectedNull: 'null'},
                        {name: 'vAlign', expectedNull: 'null'},
                        {name: 'width', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLTableElement',
                    elementToUse: document.createElement('table'),
                    attributes: [
                        {name: 'align', expectedNull: 'null'},
                        {name: 'bgColor', expectedNull: ''},
                        {name: 'border', expectedNull: 'null'},
                        {name: 'cellPadding', expectedNull: ''},
                        {name: 'cellSpacing', expectedNull: ''},
                        {name: 'frame', expectedNull: 'null'},
                        {name: 'rules', expectedNull: 'null'},
                        {name: 'summary', expectedNull: 'null'},
                        {name: 'width', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLTableRowElement',
                    elementToUse: document.createElement('tr'),
                    attributes: [
                        {name: 'align', expectedNull: 'null'},
                        {name: 'bgColor', expectedNull: ''},
                        {name: 'ch', expectedNull: 'null'},
                        {name: 'chOff', expectedNull: 'null'},
                        {name: 'vAlign', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLTableSectionElement',
                    elementToUse: document.createElement('tbody'),
                    attributes: [
                        {name: 'align', expectedNull: 'null'},
                        {name: 'ch', expectedNull: 'null'},
                        {name: 'chOff', expectedNull: 'null'},
                        {name: 'vAlign', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLTextAreaElement',
                    elementToUse: document.createElement('textarea'),
                    attributes: [
                        {name: 'defaultValue', expectedNull: 'null'},
                        {name: 'dirName', expectedNull: 'null'},
                        {name: 'name', expectedNull: 'null'},
                        {name: 'placeholder', expectedNull: 'null'},
                        {name: 'value', expectedNull: ''},
                        {name: 'wrap', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLTitleElement',
                    elementToUse: document.createElement('title'),
                    attributes: [
                        {name: 'text', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLTrackElement',
                    elementToUse: document.createElement('track'),
                    attributes: [
                        {name: 'kind', expectedNull: 'metadata'},
                        {name: 'label', expectedNull: 'null'},
                        {name: 'src', expectedNull: 'null', isUrl: true},
                        {name: 'srclang', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLUListElement',
                    elementToUse: document.createElement('ul'),
                    attributes: [
                        {name: 'type', expectedNull: 'null'}
                    ]
                },
                {
                    type: 'HTMLVideoElement',
                    elementToUse: document.createElement('video'),
                    attributes: [
                        {name: 'poster', expectedNull: 'null', isUrl: true},
                        {name: 'preload', expectedNull: 'metadata'},
                        {name: 'src', expectedNull: 'null', isUrl: true}
                    ]
                }
            ];

            for (const {type, elementToUse, attributes} of listing) {
                for (const attr of attributes)
                    nullTestElementAttribute(type, elementToUse, attr);
            }
        }
        runTests();
    </script>
